package com.dingup.mock.util;


import com.dingup.mock.enums.ReadingQuestionTypeEnum;
import com.dingup.mock.enums.SpeakingQuestionTypeEnum;
import com.dingup.mock.enums.WritingQuestionTypeEnum;
import com.dingup.mock.bean.listening.ListeningArticlePicture;
import com.dingup.mock.bean.listening.ListeningQuestionXml;
import com.dingup.mock.bean.reading.ReadingQuestionXml;
import com.dingup.mock.bean.speaking.SpeakingQuestionXml;
import com.dingup.mock.bean.writing.WritingQuestionXml;
import org.apache.commons.lang.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.ByteArrayInputStream;
import java.io.UnsupportedEncodingException;
import java.util.*;

import static com.dingup.mock.util.ConstUtil.*;
import static com.dingup.util.GConstUtil.DEFAULT_ENCODE;

public class XmlUtil {
    /**
     * 解析阅读问题XML字符串为对象
     *
     * @param xmlContent
     * @return
     */
    public static ReadingQuestionXml parseReadingQuestionXmlContent(String xmlContent) {
        ReadingQuestionXml ret = null;
        if (!StringUtils.isEmpty(xmlContent)) {
            try {
                Element root = getElementRootFromXmlContent(xmlContent);
                Element titleEle = root.element(XML_NODE_NAME_TITLE);
                Element typeEle = root.element(XML_NODE_NAME_TYPE);
                Element groupEle = root.element(XML_NODE_NAME_GROUP);
                Element answerEle = root.element(XML_NODE_NAME_ANSWER);
                Element tipEle = root.element(XML_NODE_NAME_TIP);
                Element explEle = root.element(XML_NODE_NAME_EXPL);
                Element optionsEle = root.element(XML_NODE_NAME_OPTIONS);
                if (titleEle != null
                        && typeEle != null
                        && answerEle != null
                        && !answerEle.getText().isEmpty()
                        && tipEle != null
                        && explEle != null) {
                    ret = new ReadingQuestionXml();
                    ret.setTitle(titleEle.getText());
                    ret.setType(Enum.valueOf(ReadingQuestionTypeEnum.class, typeEle.getText().toUpperCase()));
                    if (groupEle != null) {
                        ret.setGroup(groupEle.getText());
                    }
                    ret.setAnswer(Arrays.asList(answerEle.getText().split(",")));
                    ret.setTip(tipEle.getText());
                    ret.setExpl(explEle.getText());
                    if (optionsEle != null) {
                        ret.setOptions(getOptionList(optionsEle.elements()));
                    } else {
                        ret.setOptions(new HashMap<String, String>());
                    }
                }
            } catch (Exception e) {
                ret = null;
            }
        }
        return ret;
    }

    /**
     * 解析听力问题XML字符串为对象
     *
     * @param xmlContent
     * @return
     */
    public static ListeningQuestionXml parseListeningQuestionXmlContent(String xmlContent) {
        ListeningQuestionXml ret = null;
        if (!StringUtils.isEmpty(xmlContent)) {
            try {
                Element root = getElementRootFromXmlContent(xmlContent);
                Element titleEle = root.element(XML_NODE_NAME_TITLE);
                Element typeEle = root.element(XML_NODE_NAME_TYPE);
                Element answerEle = root.element(XML_NODE_NAME_ANSWER);
                Element tipEle = root.element(XML_NODE_NAME_TIP);
                Element explEle = root.element(XML_NODE_NAME_EXPL);
                Element titleAudioUrlEle = root.element(XML_NODE_NAME_TITLE_AUDIO_URL);
                Element repeatAudioUrlEle = root.element(XML_NODE_NAME_REPEAT_AUDIO_URL);
                Element optionsEle = root.element(XML_NODE_NAME_OPTIONS);
                if (titleEle != null
                        && typeEle != null
                        && answerEle != null
                        && !answerEle.getText().isEmpty()
                        && tipEle != null
                        && explEle != null
                        && titleAudioUrlEle != null
                        && repeatAudioUrlEle != null) {
                    ret = new ListeningQuestionXml();
                    // 自动为问题补充问号标记
                    String qTitle = titleEle.getText();
                    if (qTitle.lastIndexOf("?") == -1) {
                        if (qTitle.lastIndexOf(".") != -1) {
                            qTitle = qTitle.substring(0, qTitle.length() - 1);
                        }
                        qTitle += "?";
                    }
                    ret.setTitle(qTitle);
                    ret.setType(typeEle.getText().toLowerCase());
                    ret.setAnswer(Arrays.asList(answerEle.getText().split(",")));
                    ret.setTip(tipEle.getText());
                    ret.setExpl(explEle.getText());
                    ret.setTitleAudioUrl(titleAudioUrlEle.getText());
                    ret.setRepeatAudioUrl(repeatAudioUrlEle.getText());
                    if (optionsEle != null) {
                        ret.setOptions(getOptionList(optionsEle.elements()));
                    } else {
                        ret.setOptions(new HashMap<String, String>());
                    }
                }
            } catch (Exception e) {
                ret = null;
            }
        }
        return ret;
    }

    /**
     * 解析听力文章图片信息
     *
     * @param xmlContent
     * @return
     */
    public static List<ListeningArticlePicture> parseListeningArticlePicInfo(String xmlContent) {
        List<ListeningArticlePicture> retList = new ArrayList<>();
        if (!StringUtils.isEmpty(xmlContent)) {
            try {
                Element root = getElementRootFromXmlContent(xmlContent);
                List<Element> itemEleList = root.elements(XML_NODE_NAME_ITEM);
                for (Element ele : itemEleList) {
                    Element queueEle = ele.element(XML_NODE_NAME_QUEUE);
                    Element urlEle = ele.element(XML_NODE_NAME_URL);
                    Element startEle = ele.element(XML_NODE_NAME_START);
                    if (queueEle != null && urlEle != null && startEle != null) {
                        ListeningArticlePicture lap = new ListeningArticlePicture();
                        lap.setQueue(Integer.parseInt(queueEle.getText()));
                        lap.setUrl(urlEle.getText());
                        lap.setStart(Integer.parseInt(startEle.getText()));
                        retList.add(lap);
                    }
                }
            } catch (Exception e) {
                retList = null;
            }
        }
        return retList;
    }

    /**
     * 解析口语问题XML字符串为对象
     *
     * @param xmlContent
     * @return
     */
    public static SpeakingQuestionXml parseSpeakingQuestionXmlContent(String xmlContent) {
        SpeakingQuestionXml ret = null;
        if (!StringUtils.isEmpty(xmlContent)) {
            try {
                Element root = getElementRootFromXmlContent(xmlContent);
                Element titleEle = root.element(XML_NODE_NAME_TITLE);
                Element typeEle = root.element(XML_NODE_NAME_TYPE);
                Element timeEle = root.element(XML_NODE_NAME_TIME);
                Element explEle = root.element(XML_NODE_NAME_EXPL);
                Element integratedEle = root.element(XML_NODE_NAME_INTEGRATED);
                if (titleEle != null
                        && typeEle != null
                        && timeEle != null
                        && explEle != null
                        && integratedEle != null
                        && titleEle.element(XML_NODE_NAME_SCRIPT) != null
                        && titleEle.element(XML_NODE_NAME_AUDIO) != null) {
                    ret = new SpeakingQuestionXml();
                    HashMap<String, String> titleMap = new HashMap<>();
                    titleMap.put(XML_NODE_NAME_SCRIPT, titleEle.element(XML_NODE_NAME_SCRIPT).getText());
                    titleMap.put(XML_NODE_NAME_AUDIO, titleEle.element(XML_NODE_NAME_AUDIO).getText());
                    ret.setTitle(titleMap);
                    ret.setType(Enum.valueOf(SpeakingQuestionTypeEnum.class, typeEle.getText().toUpperCase()));
                    HashMap<String, Integer> timeMap = new HashMap<>();
                    timeMap.put(XML_NODE_NAME_PREPARE, Integer.parseInt(timeEle.element(XML_NODE_NAME_PREPARE).getText()));
                    timeMap.put(XML_NODE_NAME_ANSWER, Integer.parseInt(timeEle.element(XML_NODE_NAME_ANSWER).getText()));
                    ret.setTime(timeMap);
                    HashMap<String, String> explMap = new HashMap<>();
                    explMap.put(XML_NODE_NAME_SCRIPT, explEle.element(XML_NODE_NAME_SCRIPT).getText());
                    explMap.put(XML_NODE_NAME_AUDIO, explEle.element(XML_NODE_NAME_AUDIO).getText());
                    ret.setExpl(explMap);
                    HashMap<String, HashMap<String, String>> integratedMap = new HashMap<>();
                    Element readingEle = integratedEle.element(XML_NODE_NAME_READING);
                    Element listeningEle = integratedEle.element(XML_NODE_NAME_LISTENING);
                    if (readingEle != null) {
                        HashMap<String, String> readingMap = new HashMap<>();
                        readingMap.put(XML_NODE_NAME_AUDIO, readingEle.element(XML_NODE_NAME_AUDIO).getText());
                        readingMap.put(XML_NODE_NAME_TITLE, readingEle.element(XML_NODE_NAME_TITLE).getText());
                        readingMap.put(XML_NODE_NAME_CONTENT, readingEle.element(XML_NODE_NAME_CONTENT).getText());
                        integratedMap.put(XML_NODE_NAME_READING, readingMap);
                    }
                    integratedMap.put(XML_NODE_NAME_LISTENING, getListeningMap(listeningEle));
                    ret.setIntegrated(integratedMap);
                }
            } catch (Exception e) {
                ret = null;
            }
        }
        return ret;
    }

    /**
     * 解析口语问题XML字符串为对象
     *
     * @param xmlContent
     * @return
     */
    public static WritingQuestionXml parseWritingQuestionXmlContent(String xmlContent) {
        WritingQuestionXml ret = null;
        if (!StringUtils.isEmpty(xmlContent)) {
            try {
                Element root = getElementRootFromXmlContent(xmlContent);
                Element typeEle = root.element(XML_NODE_NAME_TYPE);
                Element integratedEle = root.element(XML_NODE_NAME_INTEGRATED);
                Element questionEle = root.element(XML_NODE_NAME_QUESTION);

                if (typeEle != null && integratedEle != null && questionEle != null) {
                    ret = new WritingQuestionXml();
                    ret.setType(Enum.valueOf(WritingQuestionTypeEnum.class, typeEle.getText().toUpperCase()));
                    HashMap<String, HashMap<String, String>> integratedMap = new HashMap<>();
                    Element readingEle = integratedEle.element(XML_NODE_NAME_READING);
                    Element listeningEle = integratedEle.element(XML_NODE_NAME_LISTENING);
                    if (readingEle != null) {
                        HashMap<String, String> readingMap = new HashMap<>();
                        readingMap.put(XML_NODE_NAME_CONTENT, readingEle.element(XML_NODE_NAME_CONTENT).getText());
                        integratedMap.put(XML_NODE_NAME_READING, readingMap);
                    }
                    integratedMap.put(XML_NODE_NAME_LISTENING, getListeningMap(listeningEle));
                    ret.setIntegrated(integratedMap);
                    ret.setQuestion(questionEle.getText());
                }
            } catch (Exception e) {
                ret = null;
            }
        }
        return ret;
    }

    /**
     * 解析口语和协作的listening部分节点内容
     *
     * @param listeningEle
     * @return
     */
    private static HashMap<String, String> getListeningMap(Element listeningEle) {
        HashMap<String, String> retMap = new HashMap<>();
        if (listeningEle != null) {
            retMap.put(XML_NODE_NAME_AUDIO, listeningEle.element(XML_NODE_NAME_AUDIO).getText());
            retMap.put(XML_NODE_NAME_PIC, listeningEle.element(XML_NODE_NAME_PIC).getText());
        }
        return retMap;
    }

    /**
     * 获取答案选项Map
     *
     * @param elements 节点数组
     * @return
     */
    private static HashMap<String, String> getOptionList(List<Element> elements) {
        HashMap<String, String> retMap = new HashMap<>();
        for (Element ele : elements) {
            retMap.put(ele.getName(), ele.getText());
        }
        // sort and reset.
        ArrayList<Map.Entry<String, String>> optionList = new ArrayList(retMap.entrySet());
        Collections.sort(optionList, new Comparator<Map.Entry<String, String>>() {
            public int compare(Map.Entry<String, String> o1, Map.Entry<String, String> o2) {
                return o1.getKey().compareTo(o2.getKey());
            }
        });
        retMap.clear();
        for (int i = 0; i < optionList.size(); i++) {
            retMap.put(optionList.get(i).getKey(), optionList.get(i).getValue());
        }
        return retMap;
    }

    /**
     * 根据xml字符串获取Root的Element对象
     *
     * @param xmlContent
     * @return
     * @throws UnsupportedEncodingException
     * @throws DocumentException
     */
    private static Element getElementRootFromXmlContent(String xmlContent) throws UnsupportedEncodingException, DocumentException {
        try {
            ByteArrayInputStream is = new ByteArrayInputStream(xmlContent.getBytes(DEFAULT_ENCODE));
            SAXReader saxReader = new SAXReader();
            Document doc = saxReader.read(is);
            return doc.getRootElement();
        } catch (Exception e) {
            throw e;
        }
    }

    /**
     * 生成听力图片信息xml字符串
     *
     * @param picList
     * @return
     */
    public static String genListeningArticlePicInfoXmlContent(List<ListeningArticlePicture> picList) {
        StringBuilder sb = new StringBuilder();
        if (picList != null && picList.size() > 0) {
            sb.append("<root>");
            for (ListeningArticlePicture lap : picList) {
                sb.append(
                        String.format("<item><queue>%s</queue><url>%s</url><start>%s</start></item>",
                                lap.getQueue(),
                                lap.getUrl(),
                                lap.getStart()
                        )
                );
            }
            sb.append("</root>");
        }
        return sb.toString();
    }

}
